import M from './M';

// 小工具
export default {
    classname(...anys) {
        const classes = [];
        const getType = any => Object.prototype.toString.call(any).match(/([^\s]+)]$/)[1].toLowerCase();
        const handle = (any) => {
            switch (getType(any)) {
                case 'string':
                case 'number':
                    classes.push(any);
                    break;
                case 'array':
                    any.forEach(handle);
                    break;
                case 'object':
                    Object.keys(any).forEach((key) => {
                        any[key] && classes.push(key);
                    });
                    break;
                default:
                    break;
            }
        };

        anys.forEach(handle);

        return classes.join(' ');
    },
    /**
     * 获取指定的父级元素
     * @param {*} child
     * @param {*} [root=document.body]
     * @param {*} fn
     * @returns {HTMLElement}
     */
    parent(child, root = document.body, fn) {
        let parent = child;
        // html的parentELement为null
        while (parent !== root && parent) {
            // 必须是一个HtmlElement 才会有classList/id属性
            const result = (parent instanceof HTMLElement) && fn(parent);
            if (result) {
                return parent;
            }
            parent = parent.parentElement;
        }
        return null;
    },
    style($dom, styles) {
        $dom.style.cssText += styles;
    },
    Timeout: class {
        queue = []

        add(fn, time) {
            if (time > 0) {
                let t;
                const item = (exec = true) => {
                    clearTimeout(t);
                    exec && fn();
                };
                t = setTimeout(() => {
                    fn();
                    this.queue = this.queue.filter(i => i !== item);
                }, time);
                this.queue.push(item);
            } else {
                fn();
            }
            return this;
        }

        clear() {
            this.queue.forEach(i => i(false));
            this.queue = [];
            return this;
        }

        done() {
            this.queue.forEach(i => i());
            this.queue = [];
            return this;
        }
    },
    setTimeout(fn = () => {}, time = 0) {
        if (time > 0) {
            return setTimeout(fn, time);
        }
        return fn();
    },
    // requestAnimationFrame 提升性能
    RAF(...fns) {
        fns.forEach(fn => (window.requestAnimationFrame ? requestAnimationFrame(fn) : fn()));
    },
    // 数组对比
    equalArr(arr1 = [], arr2 = []) {
        return arr1.length == arr2.length && arr1.every((i, index) => arr2[index] == i);
    },
    position(ele) {
        const eleRect = ele.getBoundingClientRect();
        const pRect = ele.parentElement.getBoundingClientRect();
        return {
            left: eleRect.left - pRect.left,
            top: eleRect.top - pRect.top,
        };
    },
    getOrigin($dom) {
        const {
            left, right, top, bottom, width, height,
        } = $dom.getBoundingClientRect();

        return {
            left, right, top, bottom, width, height,
        };
    },
    transition($doms = [], time = 0) {
        const transition = time > 0 ? `${time}s` : 'none';
        $doms.forEach((ele) => {
            ele.style.cssText += `;
                -webkit-transition: ${transition};
                transition: ${transition};
            `;
        });
    },
    getParent(child, parent) {
        // parent 可以是dom/class str/id str
        let $p = child;
        let match = false;
        while ($p !== document.body) {
            if ($p === parent) {
                match = true;
                break;
            } else {
                $p = $p.parentElement;
            }
        }
        return match ? $p : null;
    },
    /**
     * 边界校验
     * @param {4x4矩阵} [m=[]]
     * @param {原始数据} [o={}]
     * @param {边界数据} [b={}]
     * @param {最大最小缩放倍数} [{ minScale = 1, maxScale = Infinity }={}]
     * @returns
     */
    borderCheck(m = [], o = {}, b = {}, { minScale = 1, maxScale = Infinity } = {}) {
        let [S] = m;
        // 如果缩放倍数小于1，还原到1
        if (S < minScale) {
            m = M.scale(minScale / S, m);
            m[0] = minScale;
        } else if (S > maxScale) {
            m = M.scale(maxScale / S, m);
            m[m.length - 1] = maxScale;
        }

        [S] = m;

        let maxTLR = 0;
        let minTLR = 0;
        let maxTUD = 0;
        let minTUD = 0;

        // 缩放后大于基础校验宽度
        if (o.width * S > b.width) {
            maxTLR = b.left - o.left; // 因为transform-origin为left
            minTLR = maxTLR - ((o.width * S) - b.width); // 宽度差
        } else {
            // eslint-disable-next-line no-multi-assign
            maxTLR = minTLR = ((1 - S) * o.width) / 2; // 反则就以缩放元素的中心缩放
        }

        if (o.height * S > b.height) {
            maxTUD = b.top - o.top;
            minTUD = maxTUD - ((o.height * S) - b.height);
        } else {
            // eslint-disable-next-line no-multi-assign
            maxTUD = minTUD = ((1 - S) * o.height) / 2; // 反则就以缩放元素的中心缩放
        }

        const newM = [...m];

        // 获取最大，最小位移
        newM[12] = Math.max(minTLR, Math.min(maxTLR, m[12]));
        newM[13] = Math.max(minTUD, Math.min(maxTUD, m[13]));

        // newM为校正后的矩阵，
        const X = m[12] - newM[12];
        const Y = m[13] - newM[13];

        return {
            m: newM, // 边界校验后矩阵
            x: X, // X轴溢出距离
            y: Y, // Y轴溢出距离
            isOver: X !== 0 || Y !== 0, // 是否溢出
            isBigger: (o.width * S > b.width) || (o.height * S > b.height), // 被缩放对象是否大于边界尺寸
        };
    },
};
